package own.stu.jobgib.playown.fsm.easyStates.core;

import lombok.extern.slf4j.Slf4j;
import own.stu.jobgib.playown.fsm.easyStates.api.FiniteStateMachine;
import own.stu.jobgib.playown.fsm.easyStates.api.State;
import own.stu.jobgib.playown.fsm.easyStates.api.Transition;

import java.util.Set;

@Slf4j
public class FiniteStateMachineBuilder {
    //private static final Logger LOGGER = Logger.getLogger(FiniteStateMachineBuilder.class.getName());

    private final FiniteStateMachineImpl finiteStateMachine;
    private final FiniteStateMachineDefinitionValidator fsmDefinitionValidator;
    private final TransitionDefinitionValidator transitionDefinitionValidator;

    public FiniteStateMachineBuilder(Set<State> states, State initialState) {
        this.finiteStateMachine = new FiniteStateMachineImpl(states, initialState);
        this.fsmDefinitionValidator = new FiniteStateMachineDefinitionValidator();
        this.transitionDefinitionValidator = new TransitionDefinitionValidator();
    }

    /**
     * Register a transition within FSM transitions set.
     * If the transition is not valid, this method may throw an {@link IllegalArgumentException}.
     *
     * @param transition the transition to register
     * @return a configured FSM Builder instance
     */
    public FiniteStateMachineBuilder registerTransition(final Transition transition) {
        transitionDefinitionValidator.validateTransitionDefinition(transition, finiteStateMachine);
        finiteStateMachine.registerTransition(transition);
        return this;
    }

    /**
     * Register a set of transitions within FSM transitions set.
     * If a transition is not valid, this method throws an {@link IllegalArgumentException}.
     *
     * @param transitions the transitions set to register
     * @return a configured FSM Builder instance
     */
    public FiniteStateMachineBuilder registerTransitions(final Set<Transition> transitions) {
        for (Transition transition : transitions) {
            registerTransition(transition);
        }
        return this;
    }

    /**
     * Register FSM final state which is not mandatory.
     * Once in final state, the FSM will ignore all incoming events.
     *
     * @param finalState the FSM final state
     * @return a configured FSM Builder instance
     */
    public FiniteStateMachineBuilder registerFinalState(final State finalState) {
        finiteStateMachine.registerFinalState(finalState);
        return this;
    }

    /**
     * Register FSM final states set.
     * Once in final state, the FSM will ignore all incoming events.
     *
     * @param finalStates the FSM final states to register
     * @return a configured FSM Builder instance
     */
    public FiniteStateMachineBuilder registerFinalStates(final Set<State> finalStates) {
        for (State finalState : finalStates) {
            registerFinalState(finalState);
        }
        return this;
    }

    /**
     * Build a FSM instance. This method checks if FSM definition is valid.
     * If FSM state is not valid, this methods throws an {@link IllegalStateException}
     *
     * @return a configured FSM instance
     */
    public FiniteStateMachine build() {
        fsmDefinitionValidator.validateFiniteStateMachineDefinition(finiteStateMachine);
        return finiteStateMachine;
    }

    /*static {
        try {
            if (System.getProperty("java.util.logging.config.file") == null &&
                    System.getProperty("java.util.logging.config.class") == null) {
                LogManager.getLogManager().readConfiguration(FiniteStateMachineBuilder.class.getResourceAsStream("/logger/logging.properties"));
            }
        } catch (IOException e) {
            LOGGER.log(Level.WARNING, "Unable to load log configuration file", e);
        }
    }*/
}
